#!/usr/bin/env perl
use Mojolicious::Lite;
use lib 'lib';
use Schema;

my $config = plugin 'Config';

helper db => sub {
    state $db = Schema->connect(
        $ENV{ZHMO_DB} // $config->{db}{dsn} // 'dbi:SQLite:db/test.db',
        $config->{db}{user} // '',
        $config->{db}{password} // '',
        $config->{db}{dbi_attributes} // {
            sqlite_unicode  => 1,
            on_connect_call => 'use_foreign_keys',
        },
    );
    return $db;
};

get '/login' => sub {
    my $self = shift;

    $self->stash->{'title'} = 'Вход';
};

post '/login' => sub {
    my $self = shift;

    my $validation = $self->validation;
    return $self->render(text => 'Oops.', status => 400)
        unless $validation->has_data;

    $validation->required('email')->like(qr/^[\w.-]+(\@[\w.-]+)?$/);
    $validation->optional('remember')->like(qr/^[01]$/);

    return $self->render(text => 'Oops.', status => 400)
        if $validation->has_error;

    my ($email, $password, $remember) = $self->param([
        'email',
        'password',
        'remember'
    ]);

    $self->db->resultset('User')->check_pwd($email, $password)
        or return $self->redirect_to('/login');

    # тут, по-хорошему, надо использовать $sessions->secure($bool);
    my $h = $self->db->resultset('User')->by_email($email);
    $self->session($h);
    $self->session(expiration => 604800) if $remember;

    $self->redirect_to('/');
};

under sub {
    my $self = shift;

    return $self->session('id') || !$self->redirect_to('/login');
};

get '/' => sub {
    my $self = shift;

    # Заголовок таблицы на странице
    my @table = ([
        'Счёт',
        'Тип счёта',
        'Остаток',
        'Валюта',
    ]);

    push @table, $self->db->resultset('Account')->by_user_id(
        $self->session->{id},
    );

    $self->stash->{title} = 'Счета';
    $self->stash->{table} = \@table;
} => 'page';

get '/account/:id' => [id => qr/\d+/] => sub {
    my $self = shift;

    return $self->render(text => 'Oops.', status => 403)
        if not $self->db->resultset('Acl')->search(
            {
                user_id    => $self->session->{id},
                account_id => $self->param('id'),
                read       => 1,
            }
        )->count;

    # Заголовок таблицы на странице
    my @table = ([
        'Тип',
        'Время',
        'Описание',
        'Сумма',
        '',
    ]);

    push @table, $self->db->resultset('Transaction')->by_acc_id(
        $self->param('id'),
    );


    $self->stash->{title} = 'Операции';
    $self->stash->{table} = \@table;
} => 'page';

get '/transaction/delete/:id' => [id => qr/\d+/] => sub {
    my $self = shift;

    my $id = $self->param('id');

    $self->db->resultset('Transaction')->delete($id)
        or return $self->render(text => 'Oops.', status => 500);

    $self->redirect_to('/');
};

get '/transaction/new' => sub {
    my $self = shift;
    my $accounts = $self->db->resultset('Account')->id_name_by_uid(
        $self->session->{id}
    );

    return $self->render(text => 'Oops.', status => 400)
        if keys %{$accounts} < 2;

    $self->stash->{title} = 'Создать операцию';
    $self->stash->{accounts} = $accounts;
};

get '/account/new' => sub {
    my $self = shift;

    my $currencies = $self->db->resultset('Currency'   )->all;
    my $types      = $self->db->resultset('AccountType')->all;

    return $self->render(text => 'Oops.', status => 400)
        if not %{$currencies};

    return $self->render(text => 'Oops.', status => 400)
        if not %{$types};

    $self->stash->{title}      = 'Создать счёт';
    $self->stash->{types}      = $types;
    $self->stash->{currencies} = $currencies;
};

post '/transaction/new' => sub {
    my $self = shift;

    my $validation = $self->validation;
    return $self->render(text => 'Oops.', status => 400)
        unless $validation->has_data;

    return $self->render(text => 'Плохой CSRF токен!', status => 403)
        if $validation->csrf_protect->has_error('csrf_token');

    $validation->required('descr')->like(qr/^[\w\s,\.!]+$/);
    $validation->required('sum')->like(qr/^[\d ]+([,\.]\d\d)?$/);
    $validation->required('debit_id')->like(qr/^\d+$/);
    $validation->required('credit_id')->like(qr/^\d+$/);

    return $self->render(text => 'Oops.', status => 400)
        if $validation->has_error;

    return $self->render(text => 'Oops.', status => 403)
        if $self->db->resultset('Acl')->search(
            {
                user_id => $self->session->{id},
                write   => 1,
                -or     => [
                    account_id => $self->param('debit_id'),
                    account_id => $self->param('credit_id'),
                ],
            }
        )->count < 2;

    return $self->render(text => 'Oops.', status => 403)
        if $self->param('debit_id') == $self->param('credit_id');

    $self->db->resultset('Transaction')->create({
        descr               => $self->param('descr'),
        debit_id            => $self->param('debit_id'),
        credit_id           => $self->param('credit_id'),
        c_sum               => $self->param('sum'),
        d_sum               => $self->param('sum'),
        transaction_type_id => 1,
        time                => time,
    }) or return $self->render(text => 'Oops.', status => 500);

    $self->redirect_to('/');
};

post '/account/new' => sub {
    my $self = shift;

    my $validation = $self->validation;
    return $self->render(text => 'Oops.', status => 400)
        unless $validation->has_data;

    return $self->render(text => 'Плохой CSRF токен!', status => 403)
        if $validation->csrf_protect->has_error('csrf_token');

    $validation->required('name')->like(qr/^[\w\s,\.!]+$/);
    $validation->required('type_id')->like(qr/^\d+$/);
    $validation->optional('balance')->like(qr/^-?[\d ]+([,\.]\d\d)?$/);
    $validation->required('currency_id')->like(qr/^\d+$/);

    return $self->render(text => 'Oops.', status => 400)
        if $validation->has_error;

    $self->db->resultset('Account')->create({
        name                => $self->param('name'),
        account_type_id     => $self->param('type_id'),
        balance             => $self->param('balance') || 0,
        user_id             => $self->session->{id},
        currency_id         => $self->param('currency_id'),
    }) or return $self->render(text => 'Oops.', status => 500);

    $self->redirect_to('/');
};

get '/exit' => sub {
    my $self = shift;

    $self->session(expires => 1);
    $self->redirect_to('login');
};

my $secrets = $config->{secrets} // die 'secrets not found';
app->secrets($secrets);
app->sessions->default_expiration(0);

app->start;
